package com.atzz.bean;

import com.atzz.anno.Bean;
import com.atzz.anno.Di;

import java.io.DataInput;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class AnnotationApplicationContext implements ApplicationContext{

    //  创建map集合  放bean对象

    private  Map<Class,Object> beanFactory = new HashMap<>();
    private static String rootPath;

    @Override
    public Object getBean(Class clazz) {
        return beanFactory.get(clazz);
    }

    //  设置包扫描规则
    //  哪个类有bean注解  把这个类通过反射实现
    //  创建有参数的构造 传递包的路径
    public AnnotationApplicationContext(String basePackage){
        //   public static void path(String basePackage){
        try {
            // 包的路径
            //1  把. 替换成\
            String packagePath = basePackage.replaceAll("\\.", "\\\\");
            // 2获取包的绝对路径
            Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(packagePath);
            while (urls.hasMoreElements()){
                URL url = urls.nextElement();
                String filePath = URLDecoder.decode(url.getFile(), "utf-8");
                rootPath = filePath.substring(0,filePath.length()-packagePath.length());
                loanBean(new File(filePath));

            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 属性注入
        loadDi();
    }

    /**
     * 属性注入
     */
    private void loadDi() {
        //  实例化对象在 beanFactory 的map集合里面
        // 1 遍历beanFactory的map集合
        Set<Map.Entry<Class, Object>> entries = beanFactory.entrySet();
        //2 获取map集合每个对象 value  每个对象的属性获取到
        for (Map.Entry<Class, Object> entry : entries) {
            Object obj = entry.getValue();

            // 获取class对象
            Class<?> clazz = obj.getClass();

            // 获取每个对象属性 获取到
            Field[] declaredFields = clazz.getDeclaredFields();

            //3 遍历得到每个对象属性数组  得到每个属性
            for (Field field : declaredFields) {
                // 4 判断属性上面是否有dl注解
                Di annotation = field.getAnnotation(Di.class);
                if (annotation !=null){
                    //  私有的
                    field.setAccessible(true);

                    // 5 如果有dl注解 把对象进行设置 注入
                    try {
                        field.set(obj,beanFactory.get(field.getType()));
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }

            }
        }



    }

    /**
     * 包扫描过程 实例化
     * @param file
     */
    private void loanBean(File file) throws Exception {
        // 1 判断是否是文件夹
        if (file.isDirectory()){
            //  2获取文件夹里边的所有内容
            File[] childrenFiles = file.listFiles();

            // 3 判断文件夹里面为空 直接返回
            if (childrenFiles == null || childrenFiles.length == 0){
                return;
            }
            // 4 如果文件夹里边不为空 遍历问价夹里边的所有的内容
            for (File child : childrenFiles) {
                //4.1 遍历得到每个file对象  继续判断 还是问价夹  递归
                if (child.isDirectory()){
                    // 递归
                    loanBean(child);
                } else {
                    //4.2 遍历得到file对象不是文件夹 是文件
                    //4.3 得到包路径 + 类名称部分
                    String pathWithClass = child.getAbsolutePath().substring(rootPath.length() - 1);
                    // 4.4 判断当前文件类型是否.class
                    if (pathWithClass.contains(".class")){
                        // 4.5  如果是.class类型 把路径\ 替换. 把class去掉
                        String allName = pathWithClass.replaceAll("\\\\", ".")
                                .replace(".class", "");
                        //4.6 判断类上面是否有注解bean 如果有 实例化过程
                        // 4.6.1 获取类的class
                        Class<?> clazz = Class.forName(allName);
                        // 4.6.2 判断不是接口
                        if (!clazz.isInterface()){
                            // 4.6.3 判断类上面是否有注解bean
                            Bean annotation = clazz.getAnnotation(Bean.class);
                            if (annotation !=null){
                                // 4.6.4  实例化
                                Object instance = clazz.getConstructor().newInstance();
                                //4.7  把对象实例化之后 放到map集合 beanFactory
                                // 4.7.1 判断当前类如果有接口  让接口class 作为map的key
                                if (clazz.getInterfaces().length>0){
                                    beanFactory.put(clazz.getInterfaces()[0],instance);
                                }else {
                                    beanFactory.put(clazz,instance);
                                }
                            }
                        }
                    }
                }

            }


        }

    }




}
